package io.cici.cc.mybatis.lite.builder.xml;

import io.cici.cc.mybatis.lite.builder.Builder;
import io.cici.cc.mybatis.lite.builder.MapperBuilder;
import io.cici.cc.mybatis.lite.executor.keygen.Jdbc3KeyGenerator;
import io.cici.cc.mybatis.lite.executor.keygen.KeyGenerator;
import io.cici.cc.mybatis.lite.executor.keygen.NoKeyGenerator;
import io.cici.cc.mybatis.lite.executor.keygen.SelectKeyGenerator;
import io.cici.cc.mybatis.lite.mapping.MappedStatement;
import io.cici.cc.mybatis.lite.mapping.SqlCommandType;
import io.cici.cc.mybatis.lite.mapping.SqlSource;
import io.cici.cc.mybatis.lite.parse.Node;
import io.cici.cc.mybatis.lite.session.Configuration;

import java.util.List;
import java.util.Locale;


public class XmlStatementBuilder extends Builder {

    private final MapperBuilder mapperBuilder;
    private final Node node;


    public XmlStatementBuilder(Configuration configuration, MapperBuilder mapperBuilder, Node node) {
        super(configuration);
        this.mapperBuilder = mapperBuilder;
        this.node = node;

    }

    public void parseStatementNode() {
        String id = node.getStringAttribute("id");

        String nodeName = node.getNode().getNodeName();
        SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));

        XmlIncludeTransformer xmlIncludeTransformer = new XmlIncludeTransformer(configuration);
        xmlIncludeTransformer.applyIncludes(node.getNode());

        String parameterType = node.getStringAttribute("parameterType");
        Class<?> parameterTypeClass = null;
        try {
            parameterTypeClass = Class.forName(parameterType);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException();
        }

        processSelectKeyNodes(id, parameterTypeClass);


        String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        KeyGenerator keyGenerator;
        if (configuration.hasKeyGenerator(keyStatementId)) {
            keyGenerator = configuration.getKeyGenerator(keyStatementId);
        } else {
            keyGenerator = node.getBooleanAttribute("useGeneratedKeys",
                    configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
                    ? Jdbc3KeyGenerator.INSTANCE
                    : NoKeyGenerator.INSTANCE;
        }

        SqlSource sqlSource = Configuration.languageDriver.createSqlSource(configuration, node, parameterTypeClass);


        String parameterMap = node.getStringAttribute("parameterMap");
        String resultType = node.getStringAttribute("resultType");
        String resultMap = node.getStringAttribute("resultMap");
        if (resultType == null && resultMap == null) {

            throw new IllegalArgumentException("需要指定resultTypeClass resultMap");
        }
        Class<?> resultTypeClass = null;
        try {
            resultTypeClass = Class.forName(resultType);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException();
        }
        String keyProperty = node.getStringAttribute("keyProperty");
        String keyColumn = node.getStringAttribute("keyColumn");
        mapperBuilder.addMappedStatement(id, sqlSource, sqlCommandType, parameterMap,
                parameterTypeClass, resultMap, resultTypeClass, keyGenerator,
                keyProperty, keyColumn);
    }

    private void processSelectKeyNodes(String id, Class<?> parameterTypeClass) {
        List<Node> selectKeyNodes = node.evalNodeList("selectKey");

        parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass);
        removeSelectKeyNodes(selectKeyNodes);
    }

    private void parseSelectKeyNodes(String parentId, List<Node> nodeList, Class<?> parameterTypeClass) {
        for (Node node : nodeList) {
            String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;

            parseSelectKeyNode(id, node, parameterTypeClass);
        }
    }

    private void parseSelectKeyNode(String id, Node node, Class<?> parameterTypeClass) {
        String resultType = node.getStringAttribute("resultType");
        Class<?> resultTypeClass = null;
        try {
            resultTypeClass = Class.forName(resultType);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException();
        }

        String keyProperty = node.getStringAttribute("keyProperty");
        String keyColumn = node.getStringAttribute("keyColumn");
        boolean executeBefore = "BEFORE".equals(node.getStringAttribute("order", "AFTER"));


        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;

        String parameterMap = null;
        String resultMap = null;

        SqlSource sqlSource = Configuration.languageDriver.createSqlSource(configuration, node, parameterTypeClass);
        SqlCommandType sqlCommandType = SqlCommandType.SELECT;

        mapperBuilder.addMappedStatement(id, sqlSource, sqlCommandType, parameterMap,
                parameterTypeClass, resultMap, resultTypeClass, keyGenerator,
                keyProperty, keyColumn);


        MappedStatement keyStatement = configuration.getMappedStatement(id, false);
        configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
    }

    private void removeSelectKeyNodes(List<Node> nodeList) {
        for (Node node : nodeList) {
            node.getParent().getNode().removeChild(node.getNode());
        }
    }


}
